﻿/*****************************************介绍*****************************************
 * 作者：Ywh
 * 创建时间：2024-05-24 14:01:11
 * 功能：UI控件控制器
 *      1、负责查找所有需要控制的UI控件
 *      2、监听可交互控件
**************************************************************************************/

using Game.Framework;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

[DisallowMultipleComponent]
public class UIController : MonoBehaviour
{
    /// <summary>控件的尾部标记</summary>
    public const string CTRL_END = "[CTRL]";
    /// <summary>RectTransform的尾部标记</summary>
    public const string RECT_END = "[RECT]";
    /// <summary>在指定节点中断查找标记，放在头部</summary>
    public const string BREAK_HEAD = "[BREAK]";

    /// <summary>
    /// 用于存储所有要用到的UI控件，用历史替换原则 父类装子类
    /// </summary>
    private Dictionary<string, UIBehaviour> m_AllControlDic = new Dictionary<string, UIBehaviour>();
    private Dictionary<string, RectTransform> m_AllRectTransformDic = new Dictionary<string, RectTransform>();

    private void FindInChildren(Transform trans)
    {
        foreach (Transform item in trans)
        {
            bool isBreak = item.name.StartsWith(BREAK_HEAD);
            bool isRect = item.name.EndsWith(RECT_END);
            bool isCtrl = item.name.EndsWith(CTRL_END);

            if (isRect || isCtrl)
            {
                string finalName = item.name;
                if (isBreak) finalName = finalName.Substring(BREAK_HEAD.Length);

                if (isRect)
                    CollectRect(item, finalName);
                else if (isCtrl)
                    CollectCtrls(item, finalName);
            }

            if (isBreak) continue;
            FindInChildren(item);
        }
    }

    private void CollectRect(Transform item, string finalName)
    {
        finalName = finalName.Substring(0, finalName.Length - RECT_END.Length);
        if (!m_AllRectTransformDic.TryAdd(finalName, item as RectTransform))
            LogManager.LogWarning($"节点重复，将忽略，name:{item.name} ！！", "PanelBase", "FindAllRect");
        //else
        //    LogManager.Log($"name:{finalName}", "PanelBase", "AddRect");
    }

    private void CollectCtrls(Transform item, string finalName)
    {
        finalName = finalName.Substring(0, finalName.Length - CTRL_END.Length);

        var ctrls = item.GetComponents<UIBehaviour>();
        if (ctrls.Length > 0)
            for (int i = 0; i < ctrls.Length; i++)
            {
                var ctrl = ctrls[i];
                if (m_AllControlDic.TryAdd($"{finalName}{GetTypeSign(ctrl.GetType())}", ctrl))
                {
                    if (ctrl is Selectable || ctrl is ScrollRect)
                        SendMessage($"AddListening{GetTypeSign(ctrl.GetType())}", new object[] { finalName, ctrl }, SendMessageOptions.DontRequireReceiver);
                    //LogManager.Log($"name:{finalName}{GetTypeSign(ctrl.GetType())}", "PanelBase", "AddCtrl");
                }
            }
        else
            LogManager.LogWarning($"不存在UIBehaviour相关的组件，将忽略该节点，name:{item.name} ！！", "PanelBase", "FindAllCtrl");
    }

    private string GetTypeSign(Type ctrlType) => $"_{ctrlType.Name}";

    public void Init()
    {
        m_AllControlDic.Clear();
        m_AllRectTransformDic.Clear();
        FindInChildren(transform);
    }

    /// <summary>获取指定的矩形变换</summary>
    /// <param name="name">节点名称不包含<see cref="RECT_END"/> 和 <see cref="BREAK_HEAD"/>的部分</param>
    /// <param name="error">如果找不到组件则不为""</param>
    public RectTransform GetRect(string name, out string error)
    {
        error = "";
        if (!m_AllRectTransformDic.TryGetValue(name, out var result))
            error = $"不存在的RectTransform，name:{name}{RECT_END} ！！";

        return result;
    }

    /// <summary>获取指定的控件</summary>
    /// <typeparam name="T">想要获取的组件类型，例如：<see cref="Button"/></typeparam>
    /// <param name="name">节点名称不包含<see cref="CTRL_END"/> 和 <see cref="BREAK_HEAD"/>的部分</param>
    /// <param name="error">如果找不到组件则不为""</param>
    /// <returns>找不到返回null，反之返回对应类型的组件</returns>
    public T GetControl<T>(string name, out string error) where T : UIBehaviour
    {
        T result = null;
        error = "";
        if (m_AllControlDic.TryGetValue($"{name}{GetTypeSign(typeof(T))}", out var ctrl))
            result = ctrl as T;
        else
            error = $"不存在的控件，name:{name}{CTRL_END} type:{GetTypeSign(typeof(T))} ！！";

        return result;
    }

    public int RectCount => m_AllRectTransformDic.Count;

    public int CtrlCount => m_AllControlDic.Count;

    public void Clear()
    {
        foreach (var ctrl in m_AllControlDic.Values)
        {
            if (ctrl is Selectable || ctrl is ScrollRect)
                SendMessage($"RemoveListening{GetTypeSign(ctrl.GetType())}", ctrl, SendMessageOptions.DontRequireReceiver);
        }

        m_AllControlDic.Clear();
        m_AllRectTransformDic.Clear();
    }
}